# -*- Mode: Python -*-
# vim: filetype=python
#
# Copyright (C) 2018 Red Hat, Inc.
#
# Authors:
#  Daniel P. Berrange <berrange@redhat.com>
#  Laszlo Ersek <lersek@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.

##
# ********
# Firmware
# ********
##

{ 'pragma': {
    'member-name-exceptions': [
        'FirmwareArchitecture' # x86_64
    ] } }

##
# @FirmwareOSInterface:
#
# Lists the firmware-OS interface types provided by various firmware
# that is commonly used with QEMU virtual machines.
#
# @bios: Traditional x86 BIOS interface.  For example, firmware built
#     from the SeaBIOS project usually provides this interface.
#
# @openfirmware: The interface is defined by the (historical) IEEE
#     1275-1994 standard.  Examples for firmware projects that provide
#     this interface are: OpenBIOS and SLOF.
#
# @uboot: Firmware interface defined by the U-Boot project.
#
# @uefi: Firmware interface defined by the UEFI specification.  For
#     example, firmware built from the edk2 (EFI Development Kit II)
#     project usually provides this interface.
#
# Since: 3.0
##
{ 'enum' : 'FirmwareOSInterface',
  'data' : [ 'bios', 'openfirmware', 'uboot', 'uefi' ] }

##
# @FirmwareDevice:
#
# Defines the device types that firmware can be mapped into.
#
# @flash: The firmware executable and its accompanying NVRAM file are
#     to be mapped into a pflash chip each.
#
# @kernel: The firmware is to be loaded like a Linux kernel.  This is
#     similar to @memory but may imply additional processing that is
#     specific to the target architecture and machine type.
#
# @memory: The firmware is to be mapped into memory.
#
# @igvm: The firmware is defined by a file conforming to the IGVM
#     specification and mapped into memory according to directives
#     defined in the file.  This is similar to @memory but may include
#     additional processing defined by the IGVM file including initial
#     CPU state or population of metadata into the guest address
#     space.  Since: 10.1
#
# Since: 3.0
##
{ 'enum' : 'FirmwareDevice',
  'data' : [ 'flash', 'kernel', 'memory', 'igvm' ] }

##
# @FirmwareArchitecture:
#
# Enumeration of architectures for which Qemu uses additional firmware
# files.
#
# @aarch64: 64-bit Arm.
#
# @arm: 32-bit Arm.
#
# @i386: 32-bit x86.
#
# @loongarch64: 64-bit LoongArch.  (since: 7.1)
#
# @riscv64: 64-bit RISC-V.
#
# @x86_64: 64-bit x86.
#
# Since: 3.0
##
{ 'enum' : 'FirmwareArchitecture',
  'data' : [ 'aarch64', 'arm', 'i386', 'loongarch64', 'riscv64', 'x86_64' ] }

##
# @FirmwareTarget:
#
# Defines the machine types that firmware may execute on.
#
# @architecture: Determines the emulation target (the QEMU system
#     emulator) that can execute the firmware.
#
# @machines: Lists the machine types (known by the emulator that is
#     specified through @architecture) that can execute the firmware.
#     Elements of @machines are supposed to be concrete machine types,
#     not aliases.  Glob patterns are understood, which is especially
#     useful for versioned machine types.  (For example, the glob
#     pattern "pc-i440fx-*" matches "pc-i440fx-2.12".) On the QEMU
#     command line, "-machine type=..." specifies the requested
#     machine type (but that option does not accept glob patterns).
#
# Since: 3.0
##
{ 'struct' : 'FirmwareTarget',
  'data'   : { 'architecture' : 'FirmwareArchitecture',
               'machines'     : [ 'str' ] } }

##
# @FirmwareFeature:
#
# Defines the features that firmware may support, and the platform
# requirements that firmware may present.
#
# @acpi-s3: The firmware supports S3 sleep (suspend to RAM), as
#     defined in the ACPI specification.  On the "pc-i440fx-*" machine
#     types of the @i386 and @x86_64 emulation targets, S3 can be
#     enabled with "-global PIIX4_PM.disable_s3=0" and disabled with
#     "-global PIIX4_PM.disable_s3=1".  On the "pc-q35-*" machine
#     types of the @i386 and @x86_64 emulation targets, S3 can be
#     enabled with "-global ICH9-LPC.disable_s3=0" and disabled with
#     "-global ICH9-LPC.disable_s3=1".
#
# @acpi-s4: The firmware supports S4 hibernation (suspend to disk), as
#     defined in the ACPI specification.  On the "pc-i440fx-*" machine
#     types of the @i386 and @x86_64 emulation targets, S4 can be
#     enabled with "-global PIIX4_PM.disable_s4=0" and disabled with
#     "-global PIIX4_PM.disable_s4=1".  On the "pc-q35-*" machine
#     types of the @i386 and @x86_64 emulation targets, S4 can be
#     enabled with "-global ICH9-LPC.disable_s4=0" and disabled with
#     "-global ICH9-LPC.disable_s4=1".
#
# @amd-sev: The firmware supports running under AMD Secure Encrypted
#     Virtualization, as specified in the AMD64 Architecture
#     Programmer's Manual.  QEMU command line options related to this
#     feature are documented in
#     "docs/system/i386/amd-memory-encryption.rst".
#
# @amd-sev-es: The firmware supports running under AMD Secure
#     Encrypted Virtualization - Encrypted State, as specified in the
#     AMD64 Architecture Programmer's Manual.  QEMU command line
#     options related to this feature are documented in
#     "docs/system/i386/amd-memory-encryption.rst".
#
# @amd-sev-snp: The firmware supports running under AMD Secure
#     Encrypted Virtualization - Secure Nested Paging, as specified in
#     the AMD64 Architecture Programmer's Manual.  QEMU command line
#     options related to this feature are documented in
#     "docs/system/i386/amd-memory-encryption.rst".
#
# @intel-tdx: The firmware supports running under Intel Trust Domain
#     Extensions (TDX).
#
# @enrolled-keys: The variable store (NVRAM) template associated with
#     the firmware binary has the UEFI Secure Boot operational mode
#     turned on, with certificates enrolled.
#
# @requires-smm: The firmware requires the platform to emulate SMM
#     (System Management Mode), as defined in the AMD64 Architecture
#     Programmer's Manual, and in the Intel(R)64 and IA-32
#     Architectures Software Developer's Manual.  On the "pc-q35-*"
#     machine types of the @i386 and @x86_64 emulation targets, SMM
#     emulation can be enabled with "-machine smm=on".  (On the
#     "pc-q35-*" machine types of the @i386 emulation target,
#     @requires-smm presents further CPU requirements; one combination
#     known to work is "-cpu coreduo,nx=off".) If the firmware is
#     marked as both @secure-boot and @requires-smm, then write
#     accesses to the pflash chip (NVRAM) that holds the UEFI variable
#     store must be restricted to code that executes in SMM, using the
#     additional option "-global
#     driver=cfi.pflash01,property=secure,value=on".  Furthermore, a
#     large guest-physical address space (comprising guest RAM, memory
#     hotplug range, and 64-bit PCI MMIO aperture), and/or a high VCPU
#     count, may present high SMRAM requirements from the firmware.
#     On the "pc-q35-*" machine types of the @i386 and @x86_64
#     emulation targets, the SMRAM size may be increased above the
#     default 16MB with the "-global mch.extended-tseg-mbytes=uint16"
#     option.  As a rule of thumb, the default 16MB size suffices for
#     1TB of guest-phys address space and a few tens of VCPUs; for
#     every further TB of guest-phys address space, add 8MB of SMRAM.
#     48MB should suffice for 4TB of guest-phys address space and 2-3
#     hundred VCPUs.
#
# @secure-boot: The firmware implements the software interfaces for
#     UEFI Secure Boot, as defined in the UEFI specification.  Note
#     that without @requires-smm, guest code running with kernel
#     privileges can undermine the security of Secure Boot.
#
# @verbose-dynamic: When firmware log capture is enabled, the firmware
#     logs a large amount of debug messages, which may impact boot
#     performance.  With log capture disabled, there is no boot
#     performance impact.  On the "pc-i440fx-*" and "pc-q35-*" machine
#     types of the @i386 and @x86_64 emulation targets, firmware log
#     capture can be enabled with the QEMU command line options
#     "-chardev file,id=fwdebug,path=LOGFILEPATH -device
#     isa-debugcon,iobase=0x402,chardev=fwdebug".  @verbose-dynamic is
#     mutually exclusive with @verbose-static.
#
# @verbose-static: The firmware unconditionally produces a large
#     amount of debug messages, which may impact boot performance.
#     This feature may typically be carried by certain UEFI firmware
#     for the "virt-*" machine types of the @arm and @aarch64
#     emulation targets, where the debug messages are written to the
#     first (always present) PL011 UART.  @verbose-static is mutually
#     exclusive with @verbose-dynamic.
#
# @host-uefi-vars: The firmware expects the host to provide an uefi
#     variable store.  qemu supports that via "uefi-vars-sysbus"
#     (aarch64, riscv64, loongarch64) or "uefi-vars-x64" (x86_64)
#     devices.  The firmware will not use flash for nvram.  When
#     loading the firmware into flash the 'stateless' setup should be
#     used.  It is recommened to load the firmware into memory though.
#
# Since: 3.0
##
{ 'enum' : 'FirmwareFeature',
  'data' : [ 'acpi-s3', 'acpi-s4',
             'amd-sev', 'amd-sev-es', 'amd-sev-snp',
             'intel-tdx',
             'enrolled-keys', 'requires-smm',
             'secure-boot', 'host-uefi-vars',
             'verbose-dynamic', 'verbose-static' ] }

##
# @FirmwareFormat:
#
# Formats that are supported for firmware images.
#
# @raw: Raw disk image format.
#
# @qcow2: The QCOW2 image format.
#
# Since: 3.0
##
{ 'enum': 'FirmwareFormat',
  'data': [ 'raw', 'qcow2' ] }

##
# @FirmwareFlashFile:
#
# Defines common properties that are necessary for loading a firmware
# file into a pflash chip.  The corresponding QEMU command line option
# is "-drive file=@filename,format=@format".  Note however that the
# option-argument shown here is incomplete; it is completed under
# @FirmwareMappingFlash.
#
# @filename: Specifies the filename on the host filesystem where the
#     firmware file can be found.
#
# @format: Specifies the block format of the file pointed-to by
#     @filename, such as @raw or @qcow2.
#
# Since: 3.0
##
{ 'struct' : 'FirmwareFlashFile',
  'data'   : { 'filename' : 'str',
               'format'   : 'FirmwareFormat' } }


##
# @FirmwareFlashMode:
#
# Describes how the firmware build handles code versus variable
# persistence.
#
# @split: the executable file contains code while the NVRAM template
#     provides variable storage.  The executable must be configured
#     read-only and can be shared between multiple guests.  The NVRAM
#     template must be cloned for each new guest and configured
#     read-write.
#
# @combined: the executable file contains both code and variable
#     storage.  The executable must be cloned for each new guest and
#     configured read-write.  No NVRAM template will be specified.
#
# @stateless: the executable file contains code and variable storage
#     is not persisted.  The executable must be configured read-only
#     and can be shared between multiple guests.  No NVRAM template
#     will be specified.
#
# Since: 7.0.0
##
{ 'enum': 'FirmwareFlashMode',
  'data': [ 'split', 'combined', 'stateless' ] }

##
# @FirmwareMappingFlash:
#
# Describes loading and mapping properties for the firmware executable
# and its accompanying NVRAM file, when @FirmwareDevice is @flash.
#
# @mode: Describes how the firmware build handles code versus variable
#     storage.  If not present, it must be treated as if it was
#     configured with value @split.  Since: 7.0.0
#
# @executable: Identifies the firmware executable.  The @mode
#     indicates whether there will be an associated NVRAM template
#     present.  The preferred corresponding QEMU command line options
#     are
#
#     ::
#
#         -drive if=none,id=pflash0,readonly=on,file=@executable.@filename,format=@executable.@format
#         -machine pflash0=pflash0
#
#     or equivalent -blockdev instead of -drive.  When @mode is
#     @combined the executable must be cloned before use and
#     configured with readonly=off.  With QEMU versions older than
#     4.0, you have to use
#
#     ::
#
#         -drive if=pflash,unit=0,readonly=on,file=@executable.@filename,format=@executable.@format
#
# @nvram-template: Identifies the NVRAM template compatible with
#     @executable, when @mode is set to @split, otherwise it should
#     not be present.  Management software instantiates an individual
#     copy -- a specific NVRAM file -- from @nvram-template.@filename
#     for each new virtual machine definition created.
#     @nvram-template.@filename itself is never mapped into virtual
#     machines, only individual copies of it are.  An NVRAM file is
#     typically used for persistently storing the non-volatile UEFI
#     variables of a virtual machine definition.  The preferred
#     corresponding QEMU command line options are
#
#     ::
#
#         -drive if=none,id=pflash1,readonly=off,file=FILENAME_OF_PRIVATE_NVRAM_FILE,format=@nvram-template.@format
#         -machine pflash1=pflash1
#
#     or equivalent -blockdev instead of -drive.  With QEMU versions
#     older than 4.0, you have to use
#
#     ::
#
#         -drive if=pflash,unit=1,readonly=off,file=FILENAME_OF_PRIVATE_NVRAM_FILE,format=@nvram-template.@format
#
# Since: 3.0
##
{ 'struct' : 'FirmwareMappingFlash',
  'data'   : { '*mode': 'FirmwareFlashMode',
               'executable'     : 'FirmwareFlashFile',
               '*nvram-template' : 'FirmwareFlashFile' } }

##
# @FirmwareMappingKernel:
#
# Describes loading and mapping properties for the firmware
# executable, when @FirmwareDevice is @kernel.
#
# @filename: Identifies the firmware executable.  The firmware
#     executable may be shared by multiple virtual machine
#     definitions.  The corresponding QEMU command line option is
#     "-kernel @filename".
#
# Since: 3.0
##
{ 'struct' : 'FirmwareMappingKernel',
  'data'   : { 'filename' : 'str' } }

##
# @FirmwareMappingMemory:
#
# Describes loading and mapping properties for the firmware
# executable, when @FirmwareDevice is @memory.
#
# @filename: Identifies the firmware executable.  The firmware
#     executable may be shared by multiple virtual machine
#     definitions.  The corresponding QEMU command line option is
#     "-bios @filename".
#
# Since: 3.0
##
{ 'struct' : 'FirmwareMappingMemory',
  'data'   : { 'filename' : 'str' } }

##
# @FirmwareMappingIgvm:
#
# Describes loading and mapping properties for the firmware
# executable, when @FirmwareDevice is @igvm.
#
# @filename: Identifies the IGVM file containing the firmware
#     executable along with other information used to configure the
#     initial state of the guest.  The IGVM file may be shared by
#     multiple virtual machine definitions.  This corresponds to
#     creating an object on the command line with "-object igvm-cfg,
#     file=@filename".
#
# Since: 10.1
##
{ 'struct' : 'FirmwareMappingIgvm',
  'data'   : { 'filename' : 'str' } }

##
# @FirmwareMapping:
#
# Provides a discriminated structure for firmware to describe its
# loading / mapping properties.
#
# @device: Selects the device type that the firmware must be mapped
#     into.
#
# Since: 3.0
##
{ 'union'         : 'FirmwareMapping',
  'base'          : { 'device' : 'FirmwareDevice' },
  'discriminator' : 'device',
  'data'          : { 'flash'  : 'FirmwareMappingFlash',
                      'kernel' : 'FirmwareMappingKernel',
                      'memory' : 'FirmwareMappingMemory',
                      'igvm'   : 'FirmwareMappingIgvm' } }

##
# @Firmware:
#
# Describes a firmware (or a firmware use case) to management
# software.
#
# It is possible for multiple @Firmware elements to match the search
# criteria of management software.  Applications thus need rules to
# pick one of the many matches, and users need the ability to override
# distro defaults.
#
# It is recommended to create firmware JSON files (each containing a
# single @Firmware root element) with a double-digit prefix, for
# example "50-ovmf.json", "50-seabios-256k.json", etc, so they can be
# sorted in predictable order.  The firmware JSON files should be
# searched for in three directories:
#
# - /usr/share/qemu/firmware -- populated by distro-provided firmware
#                               packages (XDG_DATA_DIRS covers
#                               /usr/share by default),
#
# - /etc/qemu/firmware -- exclusively for sysadmins' local additions,
#
# - $XDG_CONFIG_HOME/qemu/firmware -- exclusively for per-user local
#                                     additions (XDG_CONFIG_HOME
#                                     defaults to $HOME/.config).
#
# Top-down, the list of directories goes from general to specific.
#
# Management software should build a list of files from all three
# locations, then sort the list by filename (i.e., last pathname
# component).  Management software should choose the first JSON file
# on the sorted list that matches the search criteria.  If a more
# specific directory has a file with same name as a less specific
# directory, then the file in the more specific directory takes
# effect.  If the more specific file is zero length, it hides the less
# specific one.
#
# For example, if a distro ships
#
# - /usr/share/qemu/firmware/50-ovmf.json
#
# - /usr/share/qemu/firmware/50-seabios-256k.json
#
# then the sysadmin can prevent the default OVMF being used at all
# with
#
#   $ touch /etc/qemu/firmware/50-ovmf.json
#
# The sysadmin can replace/alter the distro default OVMF with
#
#   $ vim /etc/qemu/firmware/50-ovmf.json
#
# or they can provide a parallel OVMF with higher priority
#
#   $ vim /etc/qemu/firmware/10-ovmf.json
#
# or they can provide a parallel OVMF with lower priority
#
#   $ vim /etc/qemu/firmware/99-ovmf.json
#
# @description: Provides a human-readable description of the firmware.
#     Management software may or may not display @description.
#
# @interface-types: Lists the types of interfaces that the firmware
#     can expose to the guest OS.  This is a non-empty, ordered list;
#     entries near the beginning of @interface-types are considered
#     more native to the firmware, and/or to have a higher quality
#     implementation in the firmware, than entries near the end of
#     @interface-types.
#
# @mapping: Describes the loading / mapping properties of the
#     firmware.
#
# @targets: Collects the target architectures (QEMU system emulators)
#     and their machine types that may execute the firmware.
#
# @features: Lists the features that the firmware supports, and the
#     platform requirements it presents.
#
# @tags: A list of auxiliary strings associated with the firmware for
#     which @description is not appropriate, due to the latter's
#     possible exposure to the end-user.  @tags serves development and
#     debugging purposes only, and management software shall
#     explicitly ignore it.
#
# Since: 3.0
#
# .. qmp-example::
#
#     {
#         "description": "SeaBIOS",
#         "interface-types": [
#             "bios"
#         ],
#         "mapping": {
#             "device": "memory",
#             "filename": "/usr/share/seabios/bios-256k.bin"
#         },
#         "targets": [
#             {
#                 "architecture": "i386",
#                 "machines": [
#                     "pc-i440fx-*",
#                     "pc-q35-*"
#                 ]
#             },
#             {
#                 "architecture": "x86_64",
#                 "machines": [
#                     "pc-i440fx-*",
#                     "pc-q35-*"
#                 ]
#             }
#         ],
#         "features": [
#             "acpi-s3",
#             "acpi-s4"
#         ],
#         "tags": [
#             "CONFIG_BOOTSPLASH=n",
#             "CONFIG_ROM_SIZE=256",
#             "CONFIG_USE_SMM=n"
#         ]
#     }
#
#     {
#         "description": "OVMF with SB+SMM, empty varstore",
#         "interface-types": [
#             "uefi"
#         ],
#         "mapping": {
#             "device": "flash",
#             "executable": {
#                 "filename": "/usr/share/OVMF/OVMF_CODE.secboot.fd",
#                 "format": "raw"
#             },
#             "nvram-template": {
#                 "filename": "/usr/share/OVMF/OVMF_VARS.fd",
#                 "format": "raw"
#             }
#         },
#         "targets": [
#             {
#                 "architecture": "x86_64",
#                 "machines": [
#                     "pc-q35-*"
#                 ]
#             }
#         ],
#         "features": [
#             "acpi-s3",
#             "amd-sev",
#             "requires-smm",
#             "secure-boot",
#             "verbose-dynamic"
#         ],
#         "tags": [
#             "-a IA32",
#             "-a X64",
#             "-p OvmfPkg/OvmfPkgIa32X64.dsc",
#             "-t GCC48",
#             "-b DEBUG",
#             "-D SMM_REQUIRE",
#             "-D SECURE_BOOT_ENABLE",
#             "-D FD_SIZE_4MB"
#         ]
#     }
#
#     {
#         "description": "OVMF with SB+SMM, SB enabled, MS certs enrolled",
#         "interface-types": [
#             "uefi"
#         ],
#         "mapping": {
#             "device": "flash",
#             "executable": {
#                 "filename": "/usr/share/OVMF/OVMF_CODE.secboot.fd",
#                 "format": "raw"
#             },
#             "nvram-template": {
#                 "filename": "/usr/share/OVMF/OVMF_VARS.secboot.fd",
#                 "format": "raw"
#             }
#         },
#         "targets": [
#             {
#                 "architecture": "x86_64",
#                 "machines": [
#                     "pc-q35-*"
#                 ]
#             }
#         ],
#         "features": [
#             "acpi-s3",
#             "amd-sev",
#             "enrolled-keys",
#             "requires-smm",
#             "secure-boot",
#             "verbose-dynamic"
#         ],
#         "tags": [
#             "-a IA32",
#             "-a X64",
#             "-p OvmfPkg/OvmfPkgIa32X64.dsc",
#             "-t GCC48",
#             "-b DEBUG",
#             "-D SMM_REQUIRE",
#             "-D SECURE_BOOT_ENABLE",
#             "-D FD_SIZE_4MB"
#         ]
#     }
#
#     {
#         "description": "OVMF with SEV-ES support",
#         "interface-types": [
#             "uefi"
#         ],
#         "mapping": {
#             "device": "flash",
#             "executable": {
#                 "filename": "/usr/share/OVMF/OVMF_CODE.fd",
#                 "format": "raw"
#             },
#             "nvram-template": {
#                 "filename": "/usr/share/OVMF/OVMF_VARS.fd",
#                 "format": "raw"
#             }
#         },
#         "targets": [
#             {
#                 "architecture": "x86_64",
#                 "machines": [
#                     "pc-q35-*"
#                 ]
#             }
#         ],
#         "features": [
#             "acpi-s3",
#             "amd-sev",
#             "amd-sev-es",
#             "verbose-dynamic"
#         ],
#         "tags": [
#             "-a X64",
#             "-p OvmfPkg/OvmfPkgX64.dsc",
#             "-t GCC48",
#             "-b DEBUG",
#             "-D FD_SIZE_4MB"
#         ]
#     }
#
#     {
#         "description": "UEFI firmware for ARM64 virtual machines",
#         "interface-types": [
#             "uefi"
#         ],
#         "mapping": {
#             "device": "flash",
#             "executable": {
#                 "filename": "/usr/share/AAVMF/AAVMF_CODE.fd",
#                 "format": "raw"
#             },
#             "nvram-template": {
#                 "filename": "/usr/share/AAVMF/AAVMF_VARS.fd",
#                 "format": "raw"
#             }
#         },
#         "targets": [
#             {
#                 "architecture": "aarch64",
#                 "machines": [
#                     "virt-*"
#                 ]
#             }
#         ],
#         "features": [
#
#         ],
#         "tags": [
#             "-a AARCH64",
#             "-p ArmVirtPkg/ArmVirtQemu.dsc",
#             "-t GCC48",
#             "-b DEBUG",
#             "-D DEBUG_PRINT_ERROR_LEVEL=0x80000000"
#         ]
#     }
##
{ 'struct' : 'Firmware',
  'data'   : { 'description'     : 'str',
               'interface-types' : [ 'FirmwareOSInterface' ],
               'mapping'         : 'FirmwareMapping',
               'targets'         : [ 'FirmwareTarget' ],
               'features'        : [ 'FirmwareFeature' ],
               'tags'            : [ 'str' ] } }
